package com.eshop.modules.system.service.impl;

import java.util.stream.Stream;
import java.lang.invoke.SerializedLambda;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.eshop.modules.system.domain.Dept;
import com.eshop.modules.system.domain.Menu;
import com.eshop.utils.StringUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import com.eshop.modules.system.service.dto.UserDto;
import com.eshop.modules.system.domain.RolesDepts;
import com.eshop.exception.EntityExistException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.eshop.modules.system.domain.RolesMenus;
import java.io.Serializable;
import java.util.Collections;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.function.Function;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import com.eshop.modules.system.service.dto.RoleSmallDto;
import java.io.IOException;
import com.eshop.utils.FileUtil;
import java.util.ArrayList;
import javax.servlet.http.HttpServletResponse;
import java.util.Iterator;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.eshop.common.utils.QueryHelpPlus;
import com.eshop.modules.system.service.dto.RoleDto;
import java.util.LinkedHashMap;
import java.util.List;
import com.github.pagehelper.PageInfo;
import java.util.Map;
import org.springframework.data.domain.Pageable;
import com.eshop.modules.system.service.dto.RoleQueryCriteria;
import com.eshop.modules.system.service.RolesDeptsService;
import com.eshop.modules.system.service.RolesMenusService;
import com.eshop.modules.system.service.mapper.DeptMapper;
import com.eshop.modules.system.service.mapper.MenuMapper;
import com.eshop.dozer.service.IGenerator;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;
import com.eshop.modules.system.service.RoleService;
import com.eshop.modules.system.domain.Role;
import com.eshop.modules.system.service.mapper.RoleMapper;
import com.eshop.common.service.impl.BaseServiceImpl;

@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = { Exception.class })
public class RoleServiceImpl extends BaseServiceImpl<RoleMapper, Role> implements RoleService
{
    private final IGenerator generator;
    private final RoleMapper roleMapper;
    private final MenuMapper menuMapper;
    private final DeptMapper deptMapper;
    private final RolesMenusService rolesMenusService;
    private final RolesDeptsService rolesDeptsService;

    public Map<String, Object> queryAll(final RoleQueryCriteria criteria, final Pageable pageable) {
        this.getPage(pageable);
        final PageInfo<Role> page = (PageInfo<Role>)new PageInfo((List)this.queryAll(criteria));
        final Map<String, Object> map = new LinkedHashMap<String, Object>(2);
        map.put("content", this.generator.convert(page.getList(), (Class)RoleDto.class));
        map.put("totalElements", page.getTotal());
        return map;
    }

    public Object queryAlls(final RoleQueryCriteria criteria, final Pageable pageable) {
        final List<Role> roleList = (List<Role>)((RoleMapper)this.baseMapper).selectList(QueryHelpPlus.getPredicate(Role.class, criteria));
        return roleList;
    }

    public List<Role> queryAll(final RoleQueryCriteria criteria) {
        final List<Role> roleList = (List<Role>)((RoleMapper)this.baseMapper).selectList(QueryHelpPlus.getPredicate(Role.class, criteria));
        for (final Role role : roleList) {
            role.setMenus(this.menuMapper.findMenuByRoleId(role.getId()));
            role.setDepts(this.deptMapper.findDeptByRoleId(role.getId()));
        }
        return roleList;
    }

    public void download(final List<RoleDto> all, final HttpServletResponse response) throws IOException {
        final List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
        for (final RoleDto role : all) {
            final Map<String, Object> map = new LinkedHashMap<String, Object>();
            map.put("名称", role.getName());
            map.put("备注", role.getRemark());
            map.put("数据权限", role.getDataScope());
            map.put("角色级别", role.getLevel());
            map.put("创建日期", role.getCreateTime());
            map.put("功能权限", role.getPermission());
            list.add(map);
        }
        FileUtil.downloadExcel((List)list, response);
    }

    public List<RoleSmallDto> findByUsersId(final Long id) {
        final List<Role> roles = this.roleMapper.selectListByUserId(id);
        return (List<RoleSmallDto>)this.generator.convert((List)roles, (Class)RoleSmallDto.class);
    }

    public Integer findByRoles(final Set<Role> roles) {
        final Set<RoleDto> roleDtos = new HashSet<RoleDto>();
        for (final Role role : roles) {
            roleDtos.add(this.findById(role.getId()));
        }
        return Collections.min((Collection<? extends Integer>)roleDtos.stream().map(RoleDto::getLevel).collect(Collectors.toList()));
    }

    public RoleDto findById(final long id) {
        final Role role = (Role)this.getById((Serializable)id);
        role.setMenus(this.menuMapper.findMenuByRoleId(role.getId()));
        role.setDepts(this.deptMapper.findDeptByRoleId(role.getId()));
        return (RoleDto)this.generator.convert(role, (Class)RoleDto.class);
    }

    public void updateMenu(final Role resources, final RoleDto roleDto) {
        if (resources.getMenus().size() > 0) {
            final List<RolesMenus> rolesMenusList = resources.getMenus().stream().map(i -> {
                RolesMenus rolesMenus = new RolesMenus();
                rolesMenus.setRoleId(resources.getId());
                rolesMenus.setMenuId(i.getId());
                return rolesMenus;
            }).collect(Collectors.toList());
            this.rolesMenusService.remove(Wrappers.<RolesMenus>lambdaQuery().eq(RolesMenus::getRoleId, resources.getId()));
            this.rolesMenusService.saveBatch((Collection)rolesMenusList);
        }
    }

    @Transactional(rollbackFor = { Exception.class })
    public RoleDto create(final Role resources) {
        if (this.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getName, resources.getName())) != null) {
            throw new EntityExistException((Class)Role.class, "username", resources.getName());
        }
        if (this.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getName, resources.getName())) != null) {
            throw new EntityExistException((Class)Role.class, "username", resources.getName());
        }
        this.save(resources);
        if (resources.getDepts().size() > 0) {
            final List<RolesDepts> rolesDeptsList = resources.getDepts().stream().map(i -> {
                RolesDepts rolesDepts = new RolesDepts();
                rolesDepts.setRoleId(resources.getId());
                rolesDepts.setDeptId(i.getId());
                return rolesDepts;
            }).collect(Collectors.toList());
            this.rolesDeptsService.saveBatch((Collection)rolesDeptsList);
        }
        return (RoleDto)this.generator.convert(resources, (Class)RoleDto.class);
    }

    @Transactional(rollbackFor = { Exception.class })
    public void update(final Role resources) {
        final Role role = (Role)this.getById((Serializable)resources.getId());
        Role role2 = (Role)this.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getName, resources.getName()));
        if (role2 != null && !role2.getId().equals(role.getId())) {
            throw new EntityExistException((Class)Role.class, "username", resources.getName());
        }
        role2 = (Role)this.getOne(Wrappers.<Role>lambdaQuery().eq(Role::getPermission, resources.getPermission()));
        if (role2 != null && !role2.getId().equals(role.getId())) {
            throw new EntityExistException((Class)Role.class, "permission", resources.getPermission());
        }
        role.setName(resources.getName());
        role.setRemark(resources.getRemark());
        role.setDataScope(resources.getDataScope());
        if (resources.getDepts().size() > 0) {
            final List<RolesDepts> rolesDeptsList = resources.getDepts().stream().map(i -> {
                RolesDepts rolesDepts = new RolesDepts();
                rolesDepts.setRoleId(resources.getId());
                rolesDepts.setDeptId(i.getId());
                return rolesDepts;
            }).collect(Collectors.toList());
            this.rolesDeptsService.remove(Wrappers.<RolesDepts>lambdaQuery().eq(RolesDepts::getRoleId, resources.getId()));
            this.rolesDeptsService.saveBatch((Collection)rolesDeptsList);
        }
        role.setLevel(resources.getLevel());
        role.setPermission(resources.getPermission());
        this.saveOrUpdate(role);
    }

    public Collection<SimpleGrantedAuthority> mapToGrantedAuthorities(final UserDto user) {
        final Set<Role> roles = this.roleMapper.findByUsers_Id(user.getId());
        for (final Role role2 : roles) {
            final Set<Menu> menuSet = this.menuMapper.findMenuByRoleId(role2.getId());
            role2.setMenus(menuSet);
            final Set<Dept> deptSet = this.deptMapper.findDeptByRoleId(role2.getId());
            role2.setDepts(deptSet);
        }
        final Set<String> permissions = roles.stream().filter(role -> StringUtils.isNotBlank(role.getPermission())).map(Role::getPermission).collect(Collectors.toSet());
        roles.stream().flatMap(role -> role.getMenus().stream()).filter(menu -> StringUtils.isNotBlank((CharSequence)menu.getPermission())).forEach(menu -> {
            String[] split = StringUtils.split(menu.getPermission(), ",");
            for (int i = 0; i < split.length; ++i){
                String permission =split[i];
                permissions.add(permission);
            }
            return;
        });
        return permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = { Exception.class })
    public void delete(final Set<Long> ids) {
        for (final Long id : ids) {
            ((LambdaUpdateChainWrapper)this.rolesMenusService.lambdaUpdate().eq(RolesMenus::getRoleId, id)).remove();
            ((LambdaUpdateChainWrapper)this.rolesDeptsService.lambdaUpdate().eq(RolesDepts::getRoleId, id)).remove();
        }
        this.removeByIds((Collection)ids);
    }

    public RoleServiceImpl(final IGenerator generator, final RoleMapper roleMapper, final MenuMapper menuMapper, final DeptMapper deptMapper, final RolesMenusService rolesMenusService, final RolesDeptsService rolesDeptsService) {
        this.generator = generator;
        this.roleMapper = roleMapper;
        this.menuMapper = menuMapper;
        this.deptMapper = deptMapper;
        this.rolesMenusService = rolesMenusService;
        this.rolesDeptsService = rolesDeptsService;
    }
}
